/***********************************************************************************
Copy right:	    hqyj Tech.
Author:         jiaoyue
Date:           2023.07.01
Description:    http请求处理
***********************************************************************************/
 
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <stdio.h>
#include <modbus.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <sys/msg.h>
#include "custom_handle.h"
#include "cJSON.h"
 

#define KB 1024
#define HTML_SIZE (64 * KB)

//普通的文本回复需要增加html头部
#define HTML_HEAD "Content-Type: text/html\r\n" \
				  "Connection: close\r\n"

union val_t
{ 
    int b_val;  //bool类型存储空间
    int i_val;   //整形值存储空间
    float f_val;  //浮点值存储空间
}vt;
struct std_node
{
	int key;  //唯一键值
	int type;  //数据点类型
    int dev_type;  //数据点属于哪个设备，根据网关支持的设备自行定义
	union val_t old_val;  //变化上报后需要更新旧值
    union val_t new_val;  //从共享内存取出最新数据，放到new_val中
    int ret;  //默认为-1，采集成功后设置为0，采集失败再置-1
};
struct msg
{
    long type;
    int key;
    union val_t val;
};

key_t key;
static int handle_login(int sock, const char *input)
{
    char reply_buf[HTML_SIZE] = {0};
    char *uname = strstr(input, "username=");
    uname += strlen("username=");
    char *p = strstr(input, "password");
    *(p - 1) = '\0';
    printf("username = %s\n", uname);

    char *passwd = p + strlen("password=");
    printf("passwd = %s\n", passwd);

    if(strcmp(uname, "admin")==0 && strcmp(passwd, "123456")==0)
    {
        sprintf(reply_buf, "<script>localStorage.setItem('usr_user_name', '%s');</script>", uname);
        strcat(reply_buf, "<script>window.location.href = '/temp.html';</script>");
        send(sock,reply_buf,strlen(reply_buf),0);
    }
    else
    {
        printf("web login failed\n");

        //"用户名或密码错误"提示，chrome浏览器直接输送utf-8字符流乱码，没有找到太好解决方案，先过渡
        char out[128] = {0xd3,0xc3,0xbb,0xa7,0xc3,0xfb,0xbb,0xf2,0xc3,0xdc,0xc2,0xeb,0xb4,0xed,0xce,0xf3};
        sprintf(reply_buf, "<script charset='gb2312'>alert('%s');</script>", out);
        strcat(reply_buf, "<script>window.location.href = '/login.html';</script>");
        send(sock,reply_buf,strlen(reply_buf),0);
    }

    return 0;
}

static int handle_add(int sock, const char *input)
{
    int number1, number2;
    
    //input必须是"data1=1data2=6"类似的格式，注意前端过来的字符串会有双引号
    sscanf(input, "\"=%ddata2=%d\"", &number1, &number2);
    printf("num1 = %d\n", number1);
    printf("num2 = %d\n", number2);

    char reply_buf[HTML_SIZE] = {0};
    printf("num = %d\n", number1+number2);
    sprintf(reply_buf, "%d", number1+number2);
    printf("resp = %s\n", reply_buf);
    send(sock,reply_buf,strlen(reply_buf),0);

    return 0;
}

static int handle_get(int sock, const char *input)
{
    int shmid;

    //创建key值
    key = ftok("/tmp/ipc/shmem/shm", 'j');
    if (key < 0)
    {
        perror("ftok err");
        return -1;
    }
    printf("key: %#x\n", key);

    //创建或打开共享内存
    shmid = shmget(key, 1024, IPC_CREAT | 0666); //没有则创建共享内存，已有则返回-1
    printf("%d\n",shmid);
    if (shmid <= 0)
    {
        if (errno == EEXIST)                //如果已存在则直接打开共享内存
            shmid = shmget(key, 1024, 0666); //直接打开共享内存，返回共享内存id
        else
        {
            perror("shmget err");
            return -1;
        }
    }
    printf("shmid: %d\n", shmid);

    //映射共享内存到用户空间
    int *p = (int *)shmat(shmid, NULL, 0);
    if (p == (int *)-1)
    {
        perror("shmat err");
        return -1;
    }
    struct std_node *std_data=(struct std_node *)(p+1);

    printf("tot:%d\n",*p);
    for(int i=0;i<*p;i++)
    {
        printf("I:%f\n",std_data[i].new_val.f_val);
    }
    //操作共享内存
    char reply_buf[128] = {0};
    sprintf(reply_buf,"%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f",std_data[7].new_val.f_val,std_data[8].new_val.f_val
    ,std_data[9].new_val.f_val,std_data[10].new_val.f_val,std_data[11].new_val.f_val,std_data[12].new_val.f_val,std_data[0].new_val.f_val,std_data[1].new_val.f_val);
    printf("%s\n",reply_buf);
    send(sock,reply_buf,strlen(reply_buf),0);
    return 0;
}

static int handle_set(int sock, const char *input)
{
    int msgid;
    key = ftok("/tmp/ipc/msgqueue/peer/msg", 'j');
    if (key < 0)
    {
        perror("ftok err");
        return -1;  
    }
    printf("key:%#x\n", key);
    //打开消息队列
    msgid = msgget(key, IPC_CREAT | 0666);
    if (msgid <= 0)
    {
        if (errno == EEXIST)
            msgid = msgget(key, 0666);
        else
        {
            perror("msgget err");
            return -1;
        }
    }
    printf("msgid: %d\n", msgid);
    
    struct msg msgbuf;
    // struct msgbuf msg;
    // msg.type = 10;
    // sscanf(input,"set=%d %d",&msg.num1,&msg.num2);
    
    //消息队列发布
    // 解析json
    cJSON * controlmsg = cJSON_Parse(input);
    cJSON * msgtype = cJSON_GetObjectItem(controlmsg,"type");
    msgbuf.type = msgtype->valueint;
    printf("tpye:%ld\n",msgbuf.type);
    cJSON * key = cJSON_GetObjectItem(controlmsg,"key");
    msgbuf.key = key->valueint;
    printf("key:%d\n",msgbuf.key);
    cJSON *val = cJSON_GetObjectItem(controlmsg,"val");
    // strcpy(msg.val.b_val,val->valuestring);
    msgbuf.val.b_val =atoi(val->valuestring);
    printf("val:%d\n",msgbuf.val.b_val);
    msgsnd(msgid, &msgbuf, sizeof(msgbuf) -sizeof(long), 0); //0:阻塞
    printf("val2:%d\n",msgbuf.val.b_val);
    send(sock,"ook",4,0);
    cJSON_Delete(controlmsg);
}

/**
 * @brief 处理自定义请求，在这里添加进程通信
 * @param input
 * @return
 */
int parse_and_process(int sock, const char *query_string, const char *input)
{
    //query_string不一定能用的到

    //先处理登录操作
    if(strstr(input, "username=") && strstr(input, "password="))
    {
        return handle_login(sock, input);
    }
    //处理求和请求
    else if(strstr(input, "data1=") && strstr(input, "data2="))
    {
        return handle_add(sock, input);
    }   
    else if(strstr(input, "get"))
    {
        return handle_get(sock, input);
    }
    else  //剩下的都是json请求，这个和协议有关了
    {
        // 解析前端发送的json字符串

        // 逻辑处理

        // 回复json字符串
        return handle_set(sock, input);
        // cJSON_Print(root);
       const char* json_response = "{\"message\": \"Hello, client!\"}";

        // 发送HTTP响应给客户端
        send(sock, json_response, strlen(json_response), 0);
    }

    return 0;
}
